package com.example.demo.auth;

import com.example.demo.dto.ErrorCode;
import com.example.demo.dto.ResponseValue;
import com.example.demo.entity.User;
import com.example.demo.enums.Role;
import com.example.demo.exception.IllegalAnnotationException;
import com.example.demo.service.UserService;
import com.example.demo.utils.AspectUtil;
import com.example.demo.utils.HttpUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Optional;

@Aspect
@Component
public class PermissionAspect {

    private final UserService userService;

    public PermissionAspect(UserService userService) {
        this.userService = userService;
    }

    @SuppressWarnings("EmptyMethod")
    @Pointcut("@annotation(com.example.demo.auth.Permission)")
    public void permissionPointcut(){ }

    @SuppressWarnings("EmptyMethod")
    @Pointcut("@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)")
    public void controllerPointcut(){}

    @Around("permissionPointcut() && controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 验证是否是controller中的方法
        Class<?> clz = joinPoint.getSignature().getDeclaringType();
        if(!Optional.ofNullable(clz.getDeclaredAnnotation(RestController.class)).isPresent()
                && !Optional.ofNullable(clz.getDeclaredAnnotation(Controller.class)).isPresent()) {
            throw new IllegalAnnotationException("@AuthFilter只能用于Controller中的方法");
        }

        // 获取AuthFilter注解修饰的方法
        Method method = AspectUtil.getMethodByJoinPoint(joinPoint);

        // 获取注解
        if(!Optional.ofNullable(method).isPresent())
            throw new IllegalAnnotationException("方法为null");
        Permission permission = method.getAnnotation(Permission.class);
        if(!Optional.ofNullable(permission).isPresent())
            throw new IllegalAnnotationException("@Permission不存在");
        Role[] roleList = permission.roles();

        // 不启用注解的情况
        if(!permission.enable()) {
            return joinPoint.proceed();
        }

        // 获取http请求
        Optional<HttpServletRequest> requestOpt = HttpUtil.getRequest();
        if(!requestOpt.isPresent())
            return ResponseValue.fail(ErrorCode.NO_LOGIN);

        // 获取Http请求中Header中的token
        Optional<String> tokenOpt = Optional.ofNullable(requestOpt.get().getHeader("token"));
        if(!tokenOpt.isPresent())
            return ResponseValue.fail(ErrorCode.NO_LOGIN);

        // 根据token获取user对象实例
        User user = userService.getUserByNumber(tokenOpt.get());
        Role role = user.getRole();

        if(permission.all()) {
            return joinPoint.proceed();
        }

        // 验证发起请求的用户是否具有执行该方法的权限
        for(Role r : roleList){
            if(Optional.ofNullable(role).isPresent() && role.equals(r)) {
                return joinPoint.proceed();
            }
        }

        return ResponseValue.fail(ErrorCode.NO_PERMISSION);
    }

}
